﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Zen.BlackBerry.Common;
using Zen.BlackBerry.Configuration;
using Zen.BlackBerry.Pap;
using Zen.BlackBerry.Pap.Control;
using Zen.BlackBerry.Pap.Parser;

namespace Zen.BlackBerry.Common.Test
{
	[TestClass]
	public class PapControlUnitTest
	{
		private class PushProperties : IPushProperties
		{
			#region IPushProperties Members
			public int AcknowledgementBatchSize
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int AcknowledgementMaxQueueSize
			{
				get
				{
					return 15;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int AcknowledgementPushLookupRetryDelay
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string DatabaseType
			{
				get
				{
					return "RDBMS";
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public TimeSpan DefaultDeliverBefore
			{
				get
				{
					return TimeSpan.FromDays(30);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string DtdDeclarationEnterprise
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string DtdDeclarationPublic
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string EnterprisePpgAddress
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string PublicPpgAddress
			{
				get
				{
					return "https://pushapi.eval.blackberry.com";
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int HttpConnectionTimeout
			{
				get
				{
					return 20;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public bool IsHttpPersistent
			{
				get
				{
					return true;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int HttpReadTimeout
			{
				get
				{
					return 20;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int MaxInClauseValues
			{
				get
				{
					return 20;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public char[] ParserSpecialCharacters
			{
				get
				{
					return new char[0];
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int PushAppDeleteUnsubscribeQueueSize
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int PushAppDeleteUnsubscribeTimeout
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int PushAppSubscriberDeleteTimeout
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int PushRequestDetailFindMaxResults
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public TimeSpan PushStatsUpdateFrequency
			{
				get
				{
					return TimeSpan.FromMinutes(5);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int PushStatsUpdateQueueSize
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int RegeneratePushIdMaxAttempts
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionFindMaxResults
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionMatchingMaxThreads
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionMatchingQueueSize
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionPpgSyncBatchSize
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionPpgSyncMaxThreads
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionPpgSyncQueueSize
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionPpgSyncTimeout
			{
				get
				{
					return 10;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string SubscriptionBaseUrl
			{
				get
				{
					return "https://pushapi.eval.blackberry.com";
				}
				set
				{
				}
			}

			public string SubscriptionQueryUrl
			{
				get
				{
					return string.Format("{0}/mss/PD_cpSubQuery", SubscriptionBaseUrl);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string SubscriptionDeregistrationUrl
			{
				get
				{
					return string.Format("{0}/mss/PD_cpDeregUser?pin=", SubscriptionBaseUrl);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string SubscriptionResumeUrl
			{
				get
				{
					return string.Format("{0}/mss/PD_cpSub?action=resume&pin=", SubscriptionBaseUrl);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string SubscriptionSuspendUrl
			{
				get
				{
					return string.Format("{0}/mss/PD_cpSub?action=suspend&pin=", SubscriptionBaseUrl);
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionValidationBatchSize
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionValidationHighWaterMark
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string WebSignalsDeregistrationUrl
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string WebSignalsRegistrationUrl
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string WebSignalsResumeUrl
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public string WebSignalsSuspendUrl
			{
				get
				{
					return string.Empty;
				}
				set
				{
					throw new NotImplementedException();
				}
			}

			public int SubscriptionNotifyMaxRetries
			{
				get
				{
					return 5;
				}
				set
				{
					throw new NotImplementedException();
				}
			}
			#endregion
		}

		private class IdGenerator : IIdGenerator
		{
			private int _value = 1006;

			#region IIdGenerator Members

			public string GenerateId()
			{
				Interlocked.Increment(ref _value);
				return string.Format("{0}@aeromobile.zendesigncorp.com", _value);
			}

			#endregion
		}

		public string UserName
		{
			get
			{
				// For public push set this to your RIM Application ID
				return string.Empty;
			}
		}

		public string Password
		{
			get
			{
				// For public push set this to your RIM password
				return string.Empty;
			}
		}

		public string TestDestination
		{
			get
			{
				// For public push set this to the PIN to test
				return string.Empty;
			}
		}

		[AssemblyInitialize]
		public static void InitAssembly(TestContext context)
		{
			IUnityContainer container = new UnityContainer();

			container.RegisterType<IPushProperties, PushProperties>(
				new ContainerControlledLifetimeManager());
			container.RegisterType<IIdGenerator, IdGenerator>(
				new ContainerControlledLifetimeManager());
			container.RegisterType<IBoundaryGenerator, BoundaryGenerator>(
				new ContainerControlledLifetimeManager());

			ServiceLocator.SetLocatorProvider(
				() => new UnityServiceLocator(container));
		}

		[TestMethod]
		public void PushRequestTest()
		{
			BinaryContent content = new BinaryContent(
				@"E:\Projects\2010\BlackBerryPushService\Zen.BlackBerry.Push.Core\Common\BinaryContent.cs", true);

			PushMessageControl control = new PushMessageControl(true);
			control.Addresses.Add(TestDestination);
			control.UserName = UserName;
			control.QualityOfService = DeliveryMethod.Unconfirmed;

			PapRequestMessage message = new PapRequestMessage(control, content);

			Debug.WriteLine("Message Payload");
			Debug.WriteLine(TestMessagePayload(message));

			PapMessage response = SendPapMessageAndGetResponse(message);
			Debug.WriteLine(response);
		}

		[TestMethod]
		public void BadMessageResponseTest()
		{
			string response = "<?xml version=\"1.0\"?><!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 2.1//EN\" \"http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd\"><pap><badmessage-response code=\"2000\" desc=\"Client Cababilites are not supported\" bad-message-fragment=\"Client Cababilites are not supported\"/></pap>";

			MemoryStream stream = new MemoryStream();
			StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
			writer.Write(response);
			writer.Flush();

			stream.Seek(0, SeekOrigin.Begin);
			PapMessage message = PapMessageParser.Read(stream);

			writer.Close();
		}

		[TestMethod]
		public void PushMessageResponseTest()
		{
			string response = "<?xml version=\"1.0\"?><!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 2.1//EN\" \"http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd\"><pap><push-response push-id=\"1007@aeromobile.zendesigncorp.com\" sender-address=\"http://pushapi.eval.blackberry.com/mss/PD_pushRequest\" sender-name=\"RIM Push-Data Service\" reply-time=\"2012-04-28T00:39:54Z\"><response-result code=\"1001\" desc=\"The request has been accepted for processing.\"></response-result></push-response></pap>";

			MemoryStream stream = new MemoryStream();
			StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
			writer.Write(response);
			writer.Flush();

			stream.Seek(0, SeekOrigin.Begin);
			PapMessage message = PapMessageParser.Read(stream);

			writer.Close();
		}

		private string TestMessagePayload(PapRequestMessage message)
		{
			MemoryStream stream = new MemoryStream();
			StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
			try
			{
				message.WriteTo(writer);
				writer.Flush();

				stream.Seek(0, SeekOrigin.Begin);
				StreamReader reader = new StreamReader(stream);
				return reader.ReadToEnd();
			}
			finally
			{
				writer.Close();
			}
		}

		[TestMethod]
		public void SendPPGSuspend()
		{
			string appId = UserName;
			string password = Password;
			string pin = TestDestination;

			var response = SendSubSuspend(pin);
			StreamReader reader = new StreamReader(
				response.GetResponseStream(), Encoding.UTF8);
			Debug.WriteLine(reader.ReadToEnd());
			reader.Close();
		}

		public void SendPPGUnsubscribe()
		{
		}

		private HttpWebResponse SendSubSuspend(string pin)
		{
			IPushProperties pp = ServiceLocator.Current.GetInstance<IPushProperties>();

			Uri ppgUri = new Uri(pp.SubscriptionSuspendUrl + pin);
			return SendSubMessage(ppgUri);
		}

		private HttpWebResponse SendSubResume(string pin)
		{
			IPushProperties pp = ServiceLocator.Current.GetInstance<IPushProperties>();

			Uri ppgUri = new Uri(pp.SubscriptionResumeUrl + pin);
			return SendSubMessage(ppgUri);
		}

		private HttpWebResponse SendSubDeregister(string pin)
		{
			IPushProperties pp = ServiceLocator.Current.GetInstance<IPushProperties>();

			Uri ppgUri = new Uri(pp.SubscriptionDeregistrationUrl + pin);
			return SendSubMessage(ppgUri);
		}

		private HttpWebResponse SendSubMessage(Uri ppgUri)
		{
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ppgUri);
			request.Method = "GET";

			// Setup authorization header
			string rawCredentials = string.Format("{0}:{1}", UserName, Password);
			request.Headers.Add("Authorization",
				string.Format(
					"Basic {0}",
					Convert.ToBase64String(Encoding.UTF8.GetBytes(rawCredentials))));

			return (HttpWebResponse)request.GetResponse();
		}

		private PapMessage SendPapMessageAndGetResponse(PapRequestMessage message)
		{
			IPushProperties pp = ServiceLocator.Current.GetInstance<IPushProperties>();

			Uri ppgUri = new Uri(new Uri(pp.PublicPpgAddress), "mss/PD_pushRequest");

			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
				ppgUri);
			request.Method = "POST";
			request.Headers.Add(HttpRequestHeader.ContentEncoding, "UTF-8");
			request.ContentType = message.ContentTypeForHeader;
			request.AllowWriteStreamBuffering = true;

			// Setup authorization header
			string rawCredentials = string.Format("{0}:{1}", UserName, Password);
			request.Headers.Add("Authorization",
				string.Format(
					"Basic {0}",
					Convert.ToBase64String(Encoding.UTF8.GetBytes(rawCredentials))));

			StreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.UTF8);
			message.WriteTo(writer);
			writer.Flush();
			writer.Close();
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			if (response.StatusCode == HttpStatusCode.OK)
			{
				Stream stream = response.GetResponseStream();
				//return PapMessageParser.Read(stream);

				MemoryStream memBuffer = new MemoryStream();
				stream.CopyTo(memBuffer);
				memBuffer.Seek(0, SeekOrigin.Begin);
				StreamReader reader = new StreamReader(memBuffer);
				Debug.WriteLine("Response Payload");
				Debug.WriteLine(reader.ReadToEnd());
				memBuffer.Seek(0, SeekOrigin.Begin);
				return PapMessageParser.Read(memBuffer);
			}
			else
			{
				throw new InvalidOperationException();
			}
		}
	}
}
